<?php

namespace app\api\service;

use app\api\extra\CommonCode;
use app\common\model\User;
use app\common\model\UserExtra;
use app\common\model\Users;
use think\Log;

class UserService
{

    private static $instance;

    public static function getInstance()
    {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * 验证邀请码是否存在
     * @param $code
     * @throws \think\exception\DbException
     */
    public function checkInviteCode($code)
    {
        $parentAgentInfo = UserExtra::where(['invite_code' => $code])->find();
        if (empty($parentAgentInfo)) {
            throw new \think\Exception('邀请码无效', CommonCode::PARAM_ERROR);
        }
        return $parentAgentInfo;
    }

    public function addExtra($params, $userId)
    {
        try {
            if (!UserExtra::where(['user_id' => $userId])->find()) {
                $data = [
                    'user_id' => $userId,
                    'invite_code' => $this->getInviteCode(),
                    'star' => 0,
                    'score' => 0,
                    'direct_push' => 0,
                ];
                if (isset($params['invite_code'])) {
                    $parentAgentInfo = $this->checkInviteCode($params['invite_code']);
                    $data['pid'] = $this->getDirectPush($parentAgentInfo['user_id']);
//                    $data['direct_push'] = $this->getDirectPush($parentAgentInfo['user_id']);
                    $data['direct_push'] = $parentAgentInfo['user_id'];

                    User::where('id', $parentAgentInfo['user_id'])->setInc('direct_num', 1);
                }
                $lamp = 0;
                $first_lamp_time = 0;
                $old_user = Users::where('mobile', $params['mobile'])->find();
                if(isset($old_user['star']) && $old_user['star'] >= 1){
                    $lamp =  1;
                    $first_lamp_time =  time();
                }
                $data['star'] = $old_user['star']??0;
                UserExtra::create($data);
                User::update([
                    'invite_code' => $data['invite_code'],
                    'pid' => $data['pid'],
                    'star' => $old_user['star']??0,
                    'lamp' => $lamp,
                    'first_lamp_time' => $first_lamp_time,
                    'direct_push' => $data['direct_push']
                ], ['id' => $userId]);
                $this->getUpdateAllNum($data['pid']);
                return true;
            } else {
                return false;
            }
        } catch (\Exception $e) {
            // 记录日志并返回错误信息
            Log::error('添加用户额外信息失败: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * 生成新用户邀请码
     * @return string
     * @throws \think\exception\DbException
     */
    private function getInviteCode()
    {
        $prefix = config('oem.InviteCodePrefix');
        do {
            $temp_code = $prefix . rand(10000, 99999);
        } while (UserExtra::where(['invite_code' => $temp_code])->find());

        return $temp_code;
    }
    public function getDirectPush($invite_user_id)
    {
        $first_count = User::where(['pid' => $invite_user_id])->count();
        if ($first_count < config('oem.DirectMaxNum')) {
            return $invite_user_id; // 当前节点可挂载
        }
        $descendantIds = $this->getFirstIdsByPid($invite_user_id, 50);

        $descendantIds = $this->reorderArray($descendantIds);
        // 遍历后代节点，寻找可挂载的节点
        $minChildCount = PHP_INT_MAX;
        $bestCandidate = false;
        foreach ($descendantIds as $first_id) {
            // 查询子节点数量
            $child_count = User::where('pid', $first_id)->count();

            if ($child_count < $minChildCount) {
                $minChildCount = $child_count;
                $bestCandidate = $first_id; // 更新最佳候选节点
            }
        }

        return $bestCandidate ?: false; // 返回最佳候选节点或 false
    }

    function getFirstIdsByPid($invite_user_id, $maxDepth = 5) {

        $directMaxNum = config('oem.DirectMaxNum');
        $first_ids = User::where(['pid' => $invite_user_id])
            ->order('id', 'asc')
            ->column('id');

        for ($depth = 0; $depth < $maxDepth; $depth++) {
            $list_ids = User::whereIn('pid', $first_ids)
                ->order('id', 'asc')
                ->column('id');

            if (count($list_ids) !== count($first_ids) * $directMaxNum) {
                break;
            }
            // 更新 first_ids 为当前 list_ids
            $first_ids = $list_ids;
        }

        return $first_ids;
    }

    function reorderArray($array, $groupSize = 3) {
        $result = [];
        $groups = array_chunk($array, $groupSize);

        $maxDepth = count($groups);
        for ($i = 0; $i < $groupSize; $i++) {
            for ($j = 0; $j < $maxDepth; $j++) {
                if (isset($groups[$j][$i])) {
                    $result[] = $groups[$j][$i];
                }
            }
        }

        return $result;
    }
    /**
     * 记录用户金额变更日志
     *
     * @param float $money 变更的金额
     * @param int $user_id 用户ID
     * @param string $memo 日志备注
     * @param string $type 变更类型
     * @param string $ids 相关业务ID
     * @return mixed 如果金额有变更且用户存在，则返回日志记录对象；否则返回错误信息数组
     */
    public function money($money, $user_id, $memo, $type = '', $ids = '')
    {
        $user = model('app\common\model\User')->get($user_id);
        if ($user && $money != 0) {
            $before = $user->money;
            $after = function_exists('bcadd') ? bcadd($user->money, $money, 2) : $user->money + $money;
            //写入日志
            $row = model('app\common\model\MoneyLog')->create([
                'user_id' => $user_id,
                'money' => $money, // 操作金额
                'before' => $before, // 原金额
                'after' => $after, // 增加后金额
                'memo' => $memo, // 备注
                'type' => $type, // 类型
                'service_ids' => $ids // 业务ID
            ]);
            return $row;
        } else {
            return ['code' => 500, 'msg' => '变更金额失败'];
        }
    }

    /**
     * 通过用户ID获取用户信息 更新所有相关层级上面的推荐人数
     * @param $user_id
     * @return void
     */
    public function getUpdateAllNum($user_id)
    {
        $user = User::find($user_id);
        if (!$user) {
            return;
        }

        $pid = $user->pid;
        while ($pid) {
            User::where('id', $pid)->setInc('all_user_num');
            $user = User::find($pid);
            $pid = $user ? $user->pid : null;
        }
    }
}
